home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
BBS in a Box 7
/
BBS in a Box - Macintosh - Volume VII (BBS in a Box) (January 1993).iso
/
Files
/
Tele
/
Pete Johnson
/
mehit 3.0.b15<source>.cpt
/
Backup.p
next >
Wrap
Text File
|
1991-08-01
|
63KB
|
2,030 lines
unit Backup;
interface
uses
Globals, HelloTabby, mehitFile, Centerer, FileAndStuffIt, LogUtils, UserLog, TextFiles, Debug;
var
Separator: STR255;
DEBUG: boolean; {<-------------- CHECK THIS!!!!}
procedure BackupMessages;
procedure ReadSTRs;
procedure TimeAt;
function MyGetString (Number: integer; var aString: str255): boolean;
implementation
var
WhenRcvdString: packed array[1..6] of char;
{----------------------------------------------------------------- }
function MyGetString; {(Number: integer; var aString:str255 ): boolean}
begin
if GetString(Number) <> nil then
begin
aString := GetString(Number)^^;
MyGetString := true
end
else
begin
aString := '';
MyGetString := false
end
end;
{ ---------------------------------- }
procedure ReadSTRs;
var
Counter: integer;
Options, LimitString, AgeString, BackString, ReportErrs: STR255;
UserDefaults, NewDefaults, tempString: str255;
{ ---------------------------------- }
function DecodeBulletValues (var DefaultString: str255): longint;
var
Marker: integer;
tempString: STR255;
Value: longint;
begin
Marker := pos(BULLET, DefaultString);
if Marker = 0 then
tempString := copy(DefaultString, 1, 255)
else
tempString := copy(DefaultString, 1, Marker - 1);
StringToNum(tempString, Value);
if Marker <> 0 then
DefaultString := copy(DefaultString, Marker + 1, 255)
else
DefaultString := '';
DecodeBulletValues := Value
end;
{ ---------------------------------- }
var
SettingsError: boolean;
begin
DefaultsPtr := DefaultStuffPtr(NewPtr(SizeOf(DefaultStuff)));
with DefaultsPtr^ do
begin
DNextLaunch := 'Second Sight';
DBackupPath := ':';
DTextPath := ':';
BUTextPath := ':';
MaxBUSize := '100';
TextType := 'QED1';
end;
BigLogName := 'mehit big report';
BriefLogName := 'mehit brief report';
MsgErrLogName := 'message error log';
OrphanLogName := 'message orphans';
Separator := '';
if not newExternalFile then
begin
with DefaultsPtr^ do
begin
if myGetString(500, tempString) then
DNextLaunch := tempString;
if myGetString(501, tempString) then
DBackupPath := tempString;
if myGetString(502, tempString) then
DTextPath := tempString;
if myGetString(504, tempString) then
BUTextPath := tempString;
if myGetString(505, tempString) then
MaxBUSize := tempString;
if myGetString(515, tempString) then
TextType := tempString;
end;
if myGetString(510, tempString) then
BigLogName := tempString;
if myGetString(511, tempString) then
BriefLogName := tempString;
if myGetString(512, tempString) then
MsgErrLogName := tempString;
if myGetString(513, tempString) then
OrphanLogName := tempString;
if myGetString(514, tempString) then
Separator := tempString;
end;
{ Format for Defaults string is 'XXXXXX', where positions are as follows: }
{ 1: Write to Tabby Log? (Y/N) }
{ 2: Full mehit Log? (Y/N) }
{ 3: Brief mehit Log? (Y/N) }
{ 4: Backup: Normal, Kill after, Purge, Stuff (B/K/P/0..5) }
{ 5: Log message errors? (Y/N) }
{ 6: Undelete Public Messages? (Y/N) }
{ 7: Renumber? (Y/N) }
if (not newExternalFile) & (GetString(503) <> nil) then
Defaults := GetString(503)^^
else
Defaults := 'YYY3YYY';
while length(Defaults) < 7 do
Defaults := concat(Defaults, 'Y');
UprString(Defaults, false);
with DefaultsPtr^ do
begin
if Defaults[1] = 'Y' then
WriteToTabby := true
else
WriteToTabby := false;
if Defaults[2] = 'Y' then
FullLog := true
else
FullLog := false;
if Defaults[3] = 'Y' then
BriefLog := true
else
BriefLog := false;
case Defaults[4] of
'B':
DBackupMode := Normal;
'K':
DBackupMode := Kill;
'P':
DBackupMode := Purge;
'1'..'6':
DBackupMode := BackOpts(ord(Defaults[4]) - ord('0') + 2)
end;
if Defaults[4] in ['1'..'6'] then
StuffItMode := ord(Defaults[4]) - ord('0')
else
StuffItMode := 3;
if Defaults[5] = 'Y' then
LogErrors := true
else
LogErrors := false;
if Defaults[6] = 'Y' then
Undelete := true
else
Undelete := false;
if Defaults[7] = 'Y' then
Renumber := true
else
Renumber := false;
end;
{ Format for User Defaults STR 516 is as follows: }
{ 1: Process UserLog? (Y/N) }
{ 2: Delete level? (Y/N) }
{ 3: Sort UserLog? (Y/N) }
{ 4: Skip deletes? (Y/N) }
{ 5: Zero user minutes? (Y/N) }
{ 6: Change level? (Y/N) }
{ 7: Kill inactive? (Y/N) }
{ 8: Log deletes? (Y/N) }
{ 9: One-call limit? (Y/N) }
{ 10: Use veteran flag? (Y/N) }
{ 11: Set (or clear)? (Y/N) }
{ after these 11 bytes, remainder of string consists of 9 }
{ numeric values with the folowing separators: }
{ YYYYYYYYYYY•0•0•0•0•0•0•0•0•0 }
{ 1 2 3 4 5 6 7 8 9 }
{ 1: Delete level }
{ 2: Check level }
{ 3: Change level }
{ 4: Change to level }
{ 5: Change to minutes }
{ 6: Inactive days }
{ 7: One-call days }
{ 8; Veteran calls }
{ 9: Flag to set/clear }
if (not newExternalFile) & (GetString(516) <> nil) then
UserDefaults := GetString(516)^^
else
UserDefaults := 'YYYYYYYYYYY•0•10•9•10•25•91•31•20•13';
UprString(UserDefaults, false);
with DefaultsPtr^ do
begin
if UserDefaults[1] = 'Y' then
ProcessUL := true
else
ProcessUL := false;
if UserDefaults[2] = 'Y' then
DeleteByLevel := true
else
DeleteByLevel := false;
if UserDefaults[3] = 'Y' then
SortUserLog := true
else
SortUserLog := false;
if UserDefaults[4] = 'Y' then
SkipDeletes := true
else
SkipDeletes := false;
if UserDefaults[5] = 'Y' then
ZeroMin := true
else
ZeroMin := false;
if UserDefaults[6] = 'Y' then
DoChangeLevel := true
else
DoChangeLevel := false;
if UserDefaults[7] = 'Y' then
KillOld := true
else
KillOld := false;
if UserDefaults[8] = 'Y' then
LogDeletes := true
else
LogDeletes := false;
if UserDefaults[9] = 'Y' then
KillOldOneCalls := true
else
KillOldOneCalls := false;
if UserDefaults[10] = 'Y' then
UseVetFlag := true
else
UseVetFlag := false;
if UserDefaults[11] = 'Y' then
SetVetFlag := true
else
SetVetFlag := false;
UserDefaults := copy(UserDefaults, pos(BULLET, UserDefaults) + 1, 255);
DeleteLevel := DecodeBulletValues(UserDefaults);
CheckLevel := DecodeBulletValues(UserDefaults);
ChangeLevel := DecodeBulletValues(UserDefaults);
ChangeToLevel := DecodeBulletValues(UserDefaults);
ChangeToMin := DecodeBulletValues(UserDefaults);
InactiveDays := DecodeBulletValues(UserDefaults);
OneCallDays := DecodeBulletValues(UserDefaults);
VetCalls := DecodeBulletValues(UserDefaults);
VetFlag := DecodeBulletValues(UserDefaults)
end;
{ Format for Text Defaults STR 517 is as follows: }
{ 1: Reset CallerLog? (Y/N) }
{ 2: Keep CallerLog for Days/Month? (D/M) }
{ 3: Stuff CallerLog? (N, 1..5) }
{ 4: Reset Tabby Log? (Y/N) }
{ 5: Keep Tabby Log for Days/Month? (D/M) }
{ 6: Stuff Tabby Log? (N, 1..5) }
{ after these 6 bytes, remainder of string consists of 4 }
{ numeric values with the folowing separators: }
{ YY3YY3•1•10•1•10 }
{ 1 2 3 4 }
{ 1: CL days }
{ 2: CLA days }
{ 3: TL days }
{ 4: TLA days }
if (not newExternalFile) & (GetString(517) <> nil) then
TextDefaults := GetString(517)^^
else
TextDefaults := 'YM2YM2•2•3•2•3';
UprString(TextDefaults, false);
with DefaultsPtr^ do
begin
if TextDefaults[1] = 'Y' then
ResetCL := true
else
ResetCL := false;
if TextDefaults[2] = 'D' then
DoCLADays := true
else
DoCLADays := false;
if TextDefaults[3] in ['1'..'6'] then
DoCLAStuff := StuffOpts(ord(TextDefaults[3]) - ord('0'))
else
DoCLAStuff := NoStuff;
if TextDefaults[4] = 'Y' then
ResetTL := true
else
ResetTL := false;
if TextDefaults[5] = 'D' then
DoTLADays := true
else
DoTLADays := false;
if TextDefaults[6] in ['1'..'6'] then
DoTLAStuff := StuffOpts(ord(TextDefaults[6]) - ord('0'))
else
DoTLAStuff := NoStuff;
TextDefaults := copy(TextDefaults, pos(BULLET, TextDefaults) + 1, 255);
CLDays := DecodeBulletValues(TextDefaults);
CLADays := DecodeBulletValues(TextDefaults);
TLDays := DecodeBulletValues(TextDefaults);
TLADays := DecodeBulletValues(TextDefaults)
end; { with DefaultsPtr^ do }
if (not newExternalFile) & (GetString(518) <> nil) then
NewDefaults := GetString(518)^^
else
NewDefaults := '100•61•N';
with DefaultsPtr^ do
begin
SettingsError := false;
newLimit := DecodeBulletValues(NewDefaults);
if (newLimit < -1) then
SettingsError := true;
newAge := DecodeBulletValues(NewDefaults);
if (newAge < 0) then
SettingsError := true;
if EqualString(NewDefaults, 'Y', false, false) then
newBU := true
else if EqualString(NewDefaults, 'N', false, false) then
newBU := false
else
SettingsError := true;
if SettingsError then
begin
newLimit := 100;
newAge := 61;
newBU := false
end;
end;
for Counter := 1 to SectionCount do
if (not newExternalFile) & (GetString(1000 + Sections[Counter]^^.Number) <> nil) then
begin
Options := GetString(1000 + Sections[Counter]^^.Number)^^;
LimitString := copy(Options, 1, pos('&', Options) - 1);
StringToNum(LimitString, Sections[Counter]^^.Limit);
Options := copy(Options, pos('&', Options) + 1, 255);
AgeString := copy(Options, 1, pos('&&', Options) - 1);
StringToNum(AgeString, Sections[Counter]^^.Age);
BackString := copy(Options, pos('&&', Options) + 2, 1);
UprString(BackString, false);
if BackString = 'Y' then
Sections[Counter]^^.Backup := true
else
Sections[Counter]^^.Backup := false
end
else { GetString(1000 + Sections[Counter]^^.Number) = nil }
with DefaultsPtr^ do
begin
Sections[Counter]^^.Limit := newLimit;
Sections[Counter]^^.Age := newAge;
Sections[Counter]^^.Backup := newBU
end
end; { Procedure ReadSTRs }
{-----------------------------------------------------------------}
procedure TimeAt;
{ Inserts the word 'at' in the middle of TimeStamp output }
var
SpaceLoc: integer;
Part1, Part2: STR255;
begin
TimeStamp;
SpaceLoc := pos(' ', DateString);
Part1 := copy(DateString, 1, SpaceLoc - 1);
Part2 := copy(DateString, SpaceLoc + 1, 255);
DateString := concat(Part1, ' at ', Part2);
end;
{-----------------------------------------------------------------}
function MakeTime (Index: integer; Separator: char): string;
{ Function changes three chars of DateTimeRecord to formatted time or date string }
var
MakeTimeString, LocalTemp: STR255;
begin
LocalTemp := '';
NumToString(ord(WhenRcvdString[Index + 1]), LocalTemp);
if length(LocalTemp) = 1 then
LocalTemp := concat('0', LocalTemp);
MakeTimeString := concat(LocalTemp, Separator);
NumToString(ord(WhenRcvdString[Index + 2]), LocalTemp);
if length(LocalTemp) = 1 then
LocalTemp := concat('0', LocalTemp);
MakeTimeString := concat(MakeTimeString, LocalTemp, Separator);
NumToString(ord(WhenRcvdString[Index + 3]), LocalTemp);
if length(LocalTemp) = 1 then
LocalTemp := concat('0', LocalTemp);
MakeTime := concat(MakeTimeString, LocalTemp)
end;
{-----------------------------------------------------------------}
procedure OpenEnd (TheFile: STR255; var FRefNum: integer; var FileEnd: longint; var Err: OSErr);
begin
Err := FSOpen(TheFile, DefaultVol, FRefNum);
if Err = NoErr then
Err := GetEOF(FRefNum, FileEnd);
if Err = NoErr then
Err := SetFPos(FRefNum, fsFromStart, 0);
end;
{-----------------------------------------------------------------}
procedure AddCommas (var TempString: STR255);
begin
case length(TempString) of
4, 5, 6:
insert(',', TempString, length(TempString) - 2);
7, 8, 9:
begin
insert(',', TempString, length(TempString) - 2);
insert(',', TempString, length(TempString) - 6);
end;
10, 11, 12:
begin
insert(',', TempString, length(TempString) - 2);
insert(',', TempString, length(TempString) - 6);
insert(',', TempString, length(TempString) - 10);
end;
otherwise
;
end; { case statement }
end;
{-----------------------------------------------------------------}
procedure ResetFile (TheFile: STR255; MCreator, MType: OSType; var FRefNum: integer; var FSErr: OSErr);
begin
FSErr := FSDelete(TheFile, DefaultVol);
FSErr := Create(TheFile, DefaultVol, MType, MCreator);
if FSErr = NoErr then
FSErr := FSOpen(TheFile, DefaultVol, FRefNum);
if FSErr = NoErr then
FSErr := SetFPos(FRefNum, fsFromStart, 0);
end;
{-----------------------------------------------------------------}
{$S Backup}
procedure BackupMessages;
const
Status = 1;
Section = 7;
WhenRcvd = 9;
Active = 1;
Reply = 2; { Reply flag in Status }
MaxTextLength = 30000; { Max allowed text size for a message }
MsgsSize = 9242;
HdrSize = 206;
HdrBufSize = 225; { ~45K }
Min = 32000; { The following values are used }
Med = 64000; { to set the size of TBufSize }
Max = 96000;
ManyDashes = '-------------------------------------------------------------------';
type
MsgsBuf = packed array[1..MsgsSize] of byte;
MsgsBufPtr = ^MsgsBuf;
MsgsBufHdl = ^MsgsBufPtr;
Header = packed record
Status: packed array[1..2] of Byte; { Use Status[1] only }
MsgNo: longint;
Section: packed array[1..2] of Byte; { Use Section[1] only }
TimeRcvd: packed array[1..6] of char;
MsgFrom: string[31];
MsgTo: string[31];
MsgSubject: string[41];
Destination: string[67];
BeginText: longint;
LengthText: longint;
ReplyTo: longint;
TimeSent: packed array[1..6] of char
end;
HdrBuf = packed array[1..HdrBufSize] of Header;
HdrBufPtr = ^HdrBuf;
HdrBufHdl = ^HdrBufPtr;
SectStat = record
limit: integer;
age: integer;
backup: boolean;
count: integer;
adjust: integer;
deletes: integer;
newcount: integer;
end;
ThreeLong = packed array[1..3] of longint;
var
MESSAGES, MSGHDR, MSGTXT, MESSAGESBAK, MSGHDRBAK, MSGTXTBAK: STR255;
TempString, MsgSeparator: STR255;
HdrRef, TxtRef, HdrBakRef, TxtBakRef, MsgsRef, MsgsBakRef, TextArcCount: integer;
BuffCount, DateCounter, Index, TheSection, MsgErrs, Undeletes: integer;
MsgCount, OldActiveCount, NewActiveCount: integer;
HBufIn, HBufOut, TFileIn, TFileOut, TBufSize: longint;
HdrFileEnd, TxtFileEnd, MLoc: longint;
Counter, HdrRecCount, TxtRecCount, Xfer, TempLong: longint;
ElapsedTime, NowSecs, NowDays, TempSecs: longint;
HFileIn, HFileOut, HeaderCount: longint;
TBufIn, TBufOut, TxLen, TxOffset, BULimit: longint;
LoMsgNo, HiMsgNo, LastMsgNo, TempDays: longint;
HdrHdl: HdrBufHdl;
TxtHdl: Handle;
MsgsHdl: MsgsBufHdl;
theDialog, debugDialog: DialogPtr;
OneByte: byte;
SectStats: array[1..255] of SectStat;
Deleted, HeaderErr: boolean;
DateTime: packed array[1..6] of Byte;
NowTime, TempTime: DateTimeRec;
OneHeader: Header;
ThreeLongs: ThreeLong;
SpareMem, TestMem: Handle;
item: handle;
itemtype: integer;
box, ProgressBox, StatusBox: rect;
StatusLength, LineLength, ValidCount: integer;
Orphans, Valid: boolean;
OrphanSect: array[1..255] of boolean;
OrphanTotal: integer;
MsgFndrInfo: FInfo;
MsgType, MsgCreator, HdrType, HdrCreator, TxtType, TxtCreator: OSType;
DisplayCount: integer;
DLimit, DAge, DBU, DErr: array[1..255] of integer;
{----------------------------------------------------------------- }
procedure NoMem;
var
MemDialog: DialogPtr;
MemItem: integer;
begin
if SpareMem <> nil then
DisposHandle(SpareMem);
MemDialog := GetNewDialog(1003, nil, Pointer(-1));
SetPort(MemDialog);
FrameDItem(MemDialog, Ok);
DrawDialog(MemDialog);
ModalDialog(nil, MemItem);
repeat
until MemItem = 1;
DisposDialog(MemDialog);
ExitToShell;
end;
{------------------------------}
procedure FillTxtBuff;
begin
Err := SetFPos(TxtRef, fsFromStart, TFileIn);
Xfer := TBufSize;
Err := FSRead(TxtRef, Xfer, Ptr(TxtHdl^));
TFileIn := TFileIn + Xfer;
end;
{----------------------------------------------------------------- }
procedure TransferText;
begin
if (TBufSize >= (TBufIn + TxLen)) & (TBufSize >= (TBufOut + TxLen)) then
begin
if TBufIn <> TBufOut then
begin
MoveHHi(Handle(TxtHdl));
HLock(Handle(TxtHdl));
MLoc := ord(TxtHdl^);
BlockMove(Ptr(MLoc + TBufIn), Ptr(MLoc + TBufOut), Size(TxLen));
HUnLock(Handle(TxtHdl));
end; { if TBufIn <> TBufOut }
TBufOut := TBufOut + TxLen;
end
else { (TBufSize < (TBufIn + TxLen)) or (TBufSize < (TBufOut + TxLen)) }
begin
MoveHHi(Handle(TxtHdl));
HLock(Handle(TxtHdl));
Xfer := TBufOut;
Err := SetFPos(TxtRef, FSFromStart, TFileOut);
Err := FSWrite(TxtRef, Xfer, Ptr(TxtHdl^));
HUnlock(Handle(TxtHdl));
TFileOut := TFileOut + Xfer;
TFileIn := OneHeader.BeginText;
FillTxtBuff;
TxOffset := TFileIn - Xfer;
TBufOut := TxLen;
end; { (TBufSize < (TBufIn + TxLen)) or (TBufSize >= (TBufIn + TxLen)) }
end;
{----------------------------------------------------------------- }
procedure MsgToText (ThisHeader: Header; TheTxtRef: integer);
var
ThisSection, ArcFile, NameCount, Count1: integer;
MBuffSize, TBuffSize: longint;
Temp1, Temp2, ThisSectName, ThisArchive, MsgTxtString: STR255;
MSGTXTPos: longint;
ArcTxtLoc, ArcBuffStart, ArcMLoc, ArcMBuffStart: longint;
ArcTxtPtr, ArcMBuffPtr: Ptr;
LengthByte: Byte;
begin
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
MBuffSize := ThisHeader.LengthText;
ArcMBuffPtr := NewPtr(MBuffSize);
Err := MemError;
if Err <> NoErr then
NoMem;
ArcMBuffStart := ord(ArcMBuffPtr);
ArcMLoc := 0;
TBuffSize := MBuffSize + 270; { Extra room for header, tear line }
ArcTxtPtr := NewPtr(TBuffSize);
Err := MemError;
if Err <> NoErr then
NoMem;
ArcBuffStart := ord(ArcTxtPtr);
ArcTxtLoc := 0;
with ThisHeader do
begin
ThisSection := Section[1]; { use 'good' byte }
ThisSectName := '';
for NameCount := 1 to SectionCount do
if Sections[NameCount]^^.Number = ThisSection then
ThisSectName := Sections[NameCount]^^.Name;
if ThisSectName <> '' then
begin
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
ThisArchive := concat(DefaultsPtr^.BUTextPath, ThisSectName, '.txt');
MakeTextFile(ThisArchive);
Err := FSOpen(ThisArchive, DefaultVol, ArcFile);
Err := SetFPos(ArcFile, fsFromLEOF, 0);
TempString := concat('Msg. #', stringof(MsgNo : 1), ' in *', ThisSectName, '* ');
WhenRcvdString := TimeSent;
TempString := concat(TempString, 'Posted on ', MakeTime(0, '/'), ' at ', MakeTime(3, ':'), ENDLINE);
LineLength := length(TempString);
BlockMove(Ptr(ord(@TempString) + 1), Ptr(ArcBuffStart + ArcTxtLoc), Size(LineLength));
ArcTxtLoc := ArcTxtLoc + LineLength;
TempString := concat('To: ', MsgTo, ' ', 'From: ', MsgFrom, ENDLINE);
LineLength := length(TempString);
BlockMove(Ptr(ord(@TempString) + 1), Ptr(ArcBuffStart + ArcTxtLoc), Size(LineLength));
ArcTxtLoc := ArcTxtLoc + LineLength;
TempString := concat('Subject: ', MsgSubject, ENDLINE, ' ', ENDLINE);
LineLength := length(TempString);
BlockMove(Ptr(ord(@TempString) + 1), Ptr(ArcBuffStart + ArcTxtLoc), Size(LineLength));
ArcTxtLoc := ArcTxtLoc + LineLength;
Err := SetFPos(TheTxtRef, fsFromStart, BeginText);
Err := FSRead(TheTxtRef, MBuffSize, ArcMBuffPtr);
ArcMLoc := 0;
Count1 := 0;
while Count1 < LengthText do
begin
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
LengthByte := 0; { make sure *both* bytes are 0 }
BlockMove(Ptr(ArcMBuffStart + ArcMLoc), Ptr(ord(@LengthByte) + 1), 1);
BlockMove(Ptr(ArcMBuffStart + ArcMLoc), Ptr(@MsgTxtString), LengthByte + 1);
ArcMLoc := ArcMLoc + LengthByte + 1;
MsgTxtString := concat(MsgTxtString, ENDLINE);
LineLength := length(MsgTxtString);
{ Next test ignores lines which are too long or which begin with ^A }
if (LineLength < 91) & (MsgTxtString[1] <> chr(1)) then
begin
BlockMove(Ptr(ord(@MsgTxtString) + 1), Ptr(ArcBuffStart + ArcTxtLoc), Size(LineLength));
ArcTxtLoc := ArcTxtLoc + LineLength;
end;
Count1 := Count1 + LineLength + 1;
end; { while Count1 < LengthText }
MsgTxtString := concat(MsgSeparator, Separator, ENDLINE, ENDLINE);
LineLength := length(MsgTxtString);
BlockMove(Ptr(ord(@MsgTxtString) + 1), Ptr(ArcBuffStart + ArcTxtLoc), Size(LineLength));
ArcTxtLoc := ArcTxtLoc + LineLength;
Err := FSWrite(ArcFile, ArcTxtLoc, ArcTxtPtr);
Err := FSClose(ArcFile);
end; { if ThisSectName <> '' }
end; { with ThisHeader do }
DisposPtr(ArcMBuffPtr);
DisposPtr(ArcTxtPtr);
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
end; { procedure MsgToText }
{----------------------------------------------------------------- }
function MakeReportLn (Str1: STR255; TheNumber: longint; FieldLength: integer; Commas: Boolean): STR255;
var
Str2: STR255;
begin
NumToString(TheNumber, Str2);
if Commas then
AddCommas(Str2);
Str2 := StringOf(Str2 : FieldLength);
MakeReportLn := concat(Str1, Str2);
end;
{----------------------------------------------------------------- }
procedure AddALine (AString: STR255);
begin
LineLength := length(AString);
BlockMove(Ptr(ord(@AString) + 1), Ptr(MLoc + TFileIn), Size(LineLength));
TFileIn := TFileIn + LineLength;
end;
{----------------------------------------------------------------- }
procedure WriteBigReport;
var
MLogRef, MCount, OldActiveCount, TotalLimits: integer;
ReportLine: STR255;
FreeBytes: longint;
ElapsedMin, ElapsedSec: integer;
begin
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
HUnLock(Handle(TxtHdl));
MoveHHi(Handle(TxtHdl));
HLock(Handle(TxtHdl));
MLoc := ord(TxtHdl^);
TFileIn := 0;
OldActiveCount := 0;
TotalLimits := 0;
TimeAt;
TempString := concat(DefaultsPtr^.DTextPath, BigLogName);
Err := FSDelete(TempString, DefaultVol);
MakeTextFile(TempString);
Err := FSOpen(TempString, DefaultVol, MLogRef);
TempString := concat(' mehitabel report for ', DateString, ENDLINE, ENDLINE);
AddALine(TempString);
TempString := concat(' before |-------deleted by-------| after txt', ENDLINE);
TempString := concat(TempString, ' active delete limit age err active b/u', ENDLINE, ENDLINE);
AddALine(TempString);
for MCount := 1 to SectionCount do
begin
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
ReportLine := Sections[MCount]^^.Name;
while length(ReportLine) < 25 do
ReportLine := concat(ReportLine, '.');
OldActiveCount := OldActiveCount + SectStats[Sections[MCount]^^.Number].Count;
NumToString(SectStats[Sections[MCount]^^.Number].Count, TempString);
while length(TempString) < 7 do
TempString := concat('.', TempString);
ReportLine := concat(ReportLine, TempString);
NumToString(SectStats[Sections[MCount]^^.Number].deletes, TempString);
TempString := StringOf(TempString : 7);
ReportLine := concat(ReportLine, TempString);
NumToString(DLimit[Sections[MCount]^^.Number], TempString);
TempString := StringOf(TempString : 7);
ReportLine := concat(ReportLine, TempString);
NumToString(DAge[Sections[MCount]^^.Number], TempString);
TempString := StringOf(TempString : 7);
ReportLine := concat(ReportLine, TempString);
NumToString(DErr[Sections[MCount]^^.Number], TempString);
TempString := StringOf(TempString : 7);
ReportLine := concat(ReportLine, TempString);
NumToString(SectStats[Sections[MCount]^^.Number].NewCount, TempString);
TempString := StringOf(TempString : 7);
ReportLine := concat(ReportLine, TempString);
NumToString(DBU[Sections[MCount]^^.Number], TempString);
TempString := StringOf(TempString : 7);
ReportLine := concat(ReportLine, TempString);
AddALine(concat(ReportLine, ENDLINE));
end; { for MCount := 1 to SectionCount }
ReportLine := MakeReportLn('totals', OldActiveCount, 26, true);
ReportLine := MakeReportLn(ReportLine, DeleteTotal, 7, true);
ReportLine := MakeReportLn(ReportLine, SurplusTotal, 7, true);
ReportLine := MakeReportLn(ReportLine, TooOldTotal, 7, true);
ReportLine := MakeReportLn(ReportLine, MsgErrs, 7, true);
ReportLine := MakeReportLn(ReportLine, NewActiveCount, 7, true);
ReportLine := MakeReportLn(ReportLine, TextArcCount, 7, true);
AddALine(concat(ENDLINE, ReportLine, ENDLINE, ENDLINE));
ReportLine := MakeReportLn('delete total', DeleteTotal + SurplusTotal + TooOldTotal + MsgErrs, 20, true);
AddALine(concat(ReportLine, ENDLINE));
ReportLine := MakeReportLn('undeleted', Undeletes, 23, true);
AddALine(concat(ReportLine, ENDLINE));
ReportLine := MakeReportLn('orphan total', OrphanTotal, 20, true);
AddALine(concat(ReportLine, ENDLINE, ENDLINE));
ReportLine := MakeReportLn('low message #', LoMsgNo, 19, false);
AddALine(concat(ReportLine, ENDLINE));
ReportLine := MakeReportLn('high message #', HiMsgNo, 18, false);
AddALine(concat(ReportLine, ENDLINE));
ReportLine := MakeReportLn('message space used', HFileOut + TFileOut + MsgsSize, 14, true);
AddALine(concat(ReportLine, ' bytes', ENDLINE));
Err := GetVInfo(0, StringPtr(@gVolName), DefaultVol, FreeBytes);
ReportLine := MakeReportLn('disk space free', FreeBytes, 17, true);
AddALine(concat(ReportLine, ' bytes', ENDLINE));
ElapsedMin := ElapsedTime div 60;
ElapsedSec := ElapsedTime mod 60;
NumToString(ElapsedSec, TempString);
if length(TempString) = 1 then
TempString := concat('0', TempString);
TempString := StringOf(ElapsedMin : 1, ':', TempString);
TempString := StringOf(TempString : 20);
ReportLine := concat('elapsed time', TempString);
AddALine(concat(ReportLine, ENDLINE));
Err := FSWrite(MLogRef, TFileIn, Ptr(TxtHdl^));
Err := FSClose(MLogRef);
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
end;
{------------------------------}
procedure WriteBriefReport;
var
MLogRef, MCount: integer;
ReportLine: STR255;
begin
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
HUnLock(Handle(TxtHdl));
MoveHHi(Handle(TxtHdl));
HLock(Handle(TxtHdl));
MLoc := ord(TxtHdl^);
TFileIn := 0;
TimeAt;
TempString := concat(DefaultsPtr^.DTextPath, BriefLogName);
Err := FSDelete(TempString, DefaultVol);
MakeTextFile(TempString);
Err := FSOpen(TempString, DefaultVol, MLogRef);
TempString := concat('BBS Report for ', DateString, ENDLINE, ENDLINE);
AddALine(TempString);
for MCount := 1 to SectionCount do
begin
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
ReportLine := Sections[MCount]^^.Name;
while length(ReportLine) < 25 do
ReportLine := concat(ReportLine, '.');
NumToString(SectStats[Sections[MCount]^^.Number].NewCount, TempString);
while length(TempString) < 7 do
TempString := concat('.', TempString);
ReportLine := concat(ReportLine, TempString);
TempString := concat(ReportLine, ENDLINE);
AddALine(TempString);
end; { for MCount := 1 to SectionCount }
ReportLine := 'total';
NumToString(NewActiveCount, TempString);
AddCommas(TempString);
TempString := StringOf(TempString : 27);
ReportLine := concat(ReportLine, TempString);
TempString := concat(ENDLINE, ReportLine, ENDLINE);
AddALine(TempString);
Err := FSWrite(MLogRef, TFileIn, Ptr(TxtHdl^));
Err := FSClose(MLogRef);
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
end;
{------------------------------}
procedure OrphanReport;
var
OrphanNum, OrphanCount: integer;
OrphanLog: STR255;
begin
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
OrphanLog := concat(DefaultsPtr^.DTextPath, OrphanLogName);
Err := FSDelete(OrphanLog, DefaultVol);
MakeTextFile(OrphanLog);
Err := FSOpen(OrphanLog, DefaultVol, OrphanNum);
Err := SetFPos(OrphanNum, fsFromStart, 0);
TimeAt;
TempString := concat('mehitabel orphan report for ', DateString, ENDLINE, ENDLINE);
TempString := concat(TempString, 'the following undefined message sections contain messages:', ENDLINE);
Err := WrLn(OrphanNum, TempString);
for OrphanCount := 1 to 255 do
if OrphanSect[OrphanCount] = true then
Err := WrLn(OrphanNum, StringOf(OrphanCount : 1));
Err := FSClose(OrphanNum);
end;
{------------------------------}
procedure LogMsgErrors;
var
MsgErrLog: STR255;
MsgErrNum: integer;
begin
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
MsgErrLog := concat(DefaultsPtr^.DTextPath, MsgErrLogName);
MakeTextFile(MsgErrLog);
Err := FSOpen(MsgErrLog, DefaultVol, MsgErrNum);
Err := SetFPos(MsgErrNum, fsFromLEOF, 0);
TimeStamp;
if (TheSection < 1) | (TheSection > 255) then
begin
TempString := concat(DateString, ' sectiom range error for msg #', stringOf(OneHeader.MsgNo : 1));
TempString := concat(TempString, ' in section ', stringOf(OneHeader.Section[1] : 1));
end
else if (OneHeader.MsgNo <= LoMsgNo) | (OneHeader.MsgNo <= HiMsgNo) then
begin
TempString := concat(DateString, ' number error for msg #', stringOf(OneHeader.MsgNo : 1));
TempString := concat(TempString, ' in section ', stringOf(OneHeader.Section[1] : 1));
end
else if ((OneHeader.BeginText + OneHeader.LengthText) > TxtFileEnd) then
begin
TempString := concat(DateString, ' location error for msg #', stringOf(OneHeader.MsgNo : 1));
TempString := concat(TempString, ' in section ', stringOf(OneHeader.Section[1] : 1));
end
else if (OneHeader.LengthText > MaxTextLength) | (OneHeader.LengthText < 0) then
begin
TempString := concat(DateString, ' text length error for msg #', stringOf(OneHeader.MsgNo : 1));
TempString := concat(TempString, ' in section ', stringOf(OneHeader.Section[1] : 1));
end;
Err := WrLn(MsgErrNum, TempString);
Err := FSClose(MsgErrNum);
end; { procedure LogMsgErrors }
{------------------------------}
procedure TrimTextFiles;
var
Count1, Count2, Count3, MsgErrNum: integer;
FileEnd, InPosition, OutPosition: longint;
ThisArchive: STR255;
FileError: OSErr;
begin
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
TextFont(0);
TextSize(12);
ForeColor(BlueColor);
TempString := 'mehitabel: trimming text…';
EraseRect(StatusRect);
TextBox(Pointer(ord(@TempString) + 1), length(TempString), StatusRect, teJustLeft);
for Count1 := 1 to 255 do
if SectStats[Count1].backup = true then
for Count2 := 1 to SectionCount do
if Sections[Count2]^^.Number = Count1 then
begin
FileError := NoErr;
ThisArchive := concat(DefaultsPtr^.BUTextPath, Sections[Count2]^^.Name, '.txt');
Err := FSOpen(ThisArchive, DefaultVol, TxtRef);
if Err = NoErr then { if there's an error, file doesn't exist }
begin
Err := GetEOF(TxtRef, FileEnd);
if (FileEnd > BULimit) & (Err = NoErr) then
begin
Count3 := 0;
Err := SetFPos(TxtRef, fsFromStart, FileEnd - BULimit);
{ next section skips to end of current message }
repeat
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
FileError := ReadLine(TxtRef, TempString);
if FileError = NoErr then
FileError := GetFPos(TxtRef, InPosition);
Count3 := succ(Count3); { Limit the number of lines we trash to 400 }
until (pos(MsgSeparator, TempString) > 0) | (InPosition >= FileEnd) | (Count3 > 400) | (FileError <> NoErr);
if (InPosition < FileEnd) & (FileError = NoErr) & (Err = NoErr) then
begin
TFileIn := InPosition + 1;
OutPosition := 0;
while TFileIn < FileEnd do
begin
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
FillTxtBuff; { FillTxtBuff adjusts TFileIn }
Err := SetFPos(TxtRef, fsFromStart, OutPosition);
Err := FSWrite(TxtRef, Xfer, Ptr(TxtHdl^));
OutPosition := OutPosition + Xfer;
end; { while TFileIn < FileEnd }
Err := SetEOF(TxtRef, OutPosition);
end; { if (InPosition < FileEnd) & (FileError <> NoErr) }
end; { if FileEnd > BULimit }
Err := FSClose(TxtRef);
if FileEnd = 0 then
Err := FSDelete(ThisArchive, DefaultVol);
if DefaultsPtr^.LogErrors & (FileError <> NoErr) then
begin
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
MakeTextFile(concat(DefaultsPtr^.DTextPath, MsgErrLogName));
Err := FSOpen(concat(DefaultsPtr^.DTextPath, MsgErrLogName), DefaultVol, MsgErrNum);
Err := SetFPos(MsgErrNum, fsFromLEOF, 0);
TimeStamp;
TempString := concat(DateString, ' file error in ', DefaultsPtr^.BUTextPath, Sections[Count2]^^.Name, '.txt');
Err := WrLn(MsgErrNum, TempString);
Err := FSClose(MsgErrNum);
end;
end; { if no error on open file }
end; { if Sections[Count2]^^.Number = Count1 }
end; { procedure TrimTextFiles }
{------------------------------}
function IsActive (var AHeader: Header; LocalPrivSect, NetPrivSect: integer): boolean;
const
Public = 2;
var
IsPublic, Undelete: boolean;
TempSubject: str255;
TempLong: longint;
begin
IsActive := false;
with AHeader do
begin
if (BitAnd(Status[1], Active) = 0) then
IsActive := true
else
begin
if (Section[1] <> LocalPrivSect) & (Section[1] <> NetPrivSect) then
IsPublic := true
else
IsPublic := false;
if DefaultsPtr^.Undelete then
Undelete := true
else
Undelete := false;
TempSubject := MsgSubject;
uprString(TempSubject, false);
if (Undelete & IsPublic & (pos('DELETE', TempSubject) <> 1)) then
begin
Undeletes := succ(Undeletes);
IsActive := true;
TempLong := ord(Status[1]);
BCLR(TempLong, 0);
Status[1] := ord(TempLong)
end
end
end
end;
{----------------------------------------------------------------- }
procedure ReadMESSAGES (MESSAGES: str255; var LocalPrivSect, NetPrivSect: integer);
{ Reads MESSAGES file and returns local private and net private section numbers }
const
LOCALPRIV = 1;
NETPRIV = 3;
var
MSGRefNum, MSCount, Counter: integer;
CharsToSend: longint;
MsgByte: byte;
begin
Counter := 0;
Err := FSOpen(MESSAGESPath, DefaultVol, MSGRefNum);
for MSCount := 1 to 255 do
begin
if MultiFinder & ((MSCount mod 25) = 0) then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
Err := SetFPos(MSGRefNum, fsFromStart, (97 + (MSCount - 1) * 36));
MsgByte := 0;
CharsToSend := 1;
Err := FSRead(MSGRefNum, CharsToSend, @MsgByte);
MsgByte := MsgByte div 256;
case MsgByte of
NETPRIV:
NetPrivSect := MSCount;
LOCALPRIV:
LocalPrivSect := LOCALPRIV;
otherwise
;
end; { case statement }
end; { for MSCount := 1 to 255 do }
Err := FSClose(MSGRefNum);
end;
{----------------------------------------------------------------- }
var
LocalPrivSect, NetPrivSect: integer;
CurrentNum, ReplyCounter: longint;
begin
TxtHdl := nil;
if FileExists(concat(gDefaultPath, 'mehit debug')) then
DEBUG := true
else
DEBUG := false;
theDialog := GetNewDialog(1008, nil, Pointer(-1));
setport(theDialog);
CenterDLOG(theDialog);
if DEBUG then
SetupDebug;
debugStr1 := 'Beginning';
if DEBUG then
IncrementDebug;
ForeColor(BlueColor);
ShowWindow(theDialog);
DrawDialog(theDialog);
GetDItem(theDialog, 2, ItemType, Item, ProgressBox); { UserItem guide for thermometer }
FrameRect(ProgressBox);
GetDItem(theDialog, 4, ItemType, Item, StatusRect); { UserItem guide for status messages }
TempString := 'mehitabel: backing up…';
TextBox(Pointer(ord(@TempString) + 1), length(TempString), StatusRect, teJustLeft);
GetDItem(theDialog, 5, ItemType, Item, MsgNoRect); { UserItem guide for message numbers }
GetDItem(theDialog, 3, ItemType, Item, Box); { Version string box }
TextFont(Geneva);
TextSize(9);
ForeColor(RedColor);
TempString := concat('version ', mehitVersion);
TextBox(Pointer(ord(@TempString) + 1), length(TempString), Box, teJustLeft);
TextFont(0);
TextSize(12);
ForeColor(BlueColor);
ElapsedTime := TickCount;
MsgSeparator := concat(chr(0), chr(0));
debugStr1 := 'Hello Tabby';
if DEBUG then
IncrementDebug;
HelloTabby;
UnloadSeg(@HelloTabby);
if DefaultsPtr <> nil then
DefaultsPtr^.DNextLaunch := NextLaunch;
SpareMem := NewHandle(10000); { Safety net -- this is disposed in error msg }
Err := MemError;
if Err <> NoErr then
NoMem;
debugStr1 := 'Safety net';
if DEBUG then
IncrementDebug;
GetDateTime(NowSecs);
if DefaultsPtr^.WriteToTabby then
begin
TimeStamp;
Err := FSOpen(concat(gDefaultPath, 'Tabby:Tabby Log'), DefaultVol, TLogRef);
if Err <> noErr then
begin
Err := Create(concat(gDefaultPath, 'Tabby:Tabby Log'), DefaultVol, DefaultsPtr^.TEXTType, 'TEXT');
Err := FSOpen(concat(gDefaultPath, 'Tabby:Tabby Log'), DefaultVol, TLogRef);
end;
Err := SetFPos(TLogRef, fsFromLEOF, 0);
Err := WrLn(TLogRef, concat(DateString, ' mehitabel - program starting v.', mehitVersion));
Err := FSClose(TLogRef);
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
end;
debugStr1 := 'Initializing Sect Stats';
if DEBUG then
IncrementDebug;
for Counter := 1 to 255 do
begin
SectStats[Counter].limit := 0;
SectStats[Counter].age := 0;
SectStats[Counter].backup := false;
SectStats[Counter].count := 0;
SectStats[Counter].adjust := 0;
SectStats[Counter].deletes := 0;
OrphanSect[Counter] := false;
DLimit[Counter] := 0;
DAge[Counter] := 0;
DBU[Counter] := 0;
DErr[Counter] := 0;
end;
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
for Counter := 1 to SectionCount do
with Sections[Counter]^^ do
begin
SectStats[Number].Limit := Limit;
SectStats[Number].Age := Age;
SectStats[Number].backup := Backup;
end;
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
debugStr1 := 'Stuffing messages';
if DEBUG then
IncrementDebug;
with DefaultsPtr^ do
begin
case DBackupMode of
StuffNone:
ModeString := 'none';
StuffFaster:
ModeString := 'faster';
StuffFast:
ModeString := 'fast';
StuffOptimal:
ModeString := 'optimal';
StuffBestGuess:
ModeString := 'best guess';
StuffBetter:
ModeString := 'better';
end;
if DefaultsPtr^.DBackupMode in [StuffNone..StuffBetter] then
TempString := concat('stuffing [', ModeString, ']')
else
tempString := '';
EraseRect(MsgNoRect);
TextFont(Geneva);
TextSize(9);
ForeColor(RedColor);
TextBox(Pointer(ord(@TempString) + 1), length(TempString), MsgNoRect, teJustRight);
TextFont(0);
TextSize(12);
ForeColor(BlueColor);
StuffMessages;
end;
UnloadSeg(@StuffMessages);
debugStr1 := 'Setting Message paths';
if DEBUG then
IncrementDebug;
MESSAGES := MESSAGESPath;
MSGHDR := concat(MsgPath, 'MSGHDR');
MSGTXT := concat(MsgPath, 'MSGTXT');
with DefaultsPtr^ do
begin
if DBackupPath <> '' then
begin
if DBackupPath[length(DBackupPath)] <> ':' then
DBackupPath := concat(DBackupPath, ':');
MESSAGESBAK := concat(DBackupPath, 'MESSAGES.Bak');
MSGHDRBAK := concat(DBackupPath, 'MSGHDR.Bak');
MSGTXTBAK := concat(DBackupPath, 'MSGTXT.Bak');
end
else
begin
MESSAGESBAK := concat(MESSAGESPath, '.Bak');
MSGHDRBAK := concat(MsgPath, 'MSGHDR.Bak');
MSGTXTBAK := concat(MsgPath, 'MSGTXT.Bak');
end;
end;
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
debugStr1 := 'Reading MESSAGES';
if DEBUG then
IncrementDebug;
ReadMESSAGES(MESSAGES, LocalPrivSect, NetPrivSect);
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
if not (Defaults[4] in ['P', '0'..'5']) then
begin
TempString := 'messages';
TextFont(Geneva);
TextSize(9);
ForeColor(RedColor);
TextBox(Pointer(ord(@TempString) + 1), length(TempString), MsgNoRect, teJustRight);
ForeColor(BlueColor);
MsgsHdl := MsgsBufHdl(NewHandle(sizeOf(MsgsBuf)));
Err := MemError;
if Err <> NoErr then
NoMem;
Err := GetFInfo(MESSAGES, DefaultVol, MsgFndrInfo);
MsgType := MsgFndrInfo.fdType;
MsgCreator := MsgFndrInfo.fdCreator;
OpenEnd(MESSAGES, MsgsRef, TempLong, Err);
ResetFile(MESSAGESBAK, MsgType, MsgCreator, MsgsBakRef, Err);
Xfer := MsgsSize;
Err := FSRead(MsgsRef, Xfer, Ptr(MsgsHdl^));
Err := FSWrite(MsgsBakRef, Xfer, Ptr(MsgsHdl^));
Err := FSClose(MsgsRef);
Err := FSClose(MsgsBakRef);
if (MsgsHdl <> nil) then
begin
DisposHandle(Handle(MsgsHdl));
MsgsHdl := nil
end;
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
end; { if not (Defaults[4] in ['P', '0'..'5']) }
StatusBox := ProgressBox;
InsetRect(StatusBox, 1, 1);
StatusLength := StatusBox.right - StatusBox.left;
StatusBox.right := (StatusBox.left + StatusLength div 20);
FillRect(StatusBox, Gray);
OpenEnd(MSGHDR, HdrRef, HdrFileEnd, Err);
if not (Defaults[4] in ['P', '0'..'5']) then
begin
TempString := 'msghdr';
EraseRect(MsgNoRect);
ForeColor(RedColor);
TextBox(Pointer(ord(@TempString) + 1), length(TempString), MsgNoRect, teJustRight);
ForeColor(BlueColor);
Err := GetFInfo(MSGHDR, DefaultVol, MsgFndrInfo);
HdrType := MsgFndrInfo.fdType;
HdrCreator := MsgFndrInfo.fdCreator;
ResetFile(MSGHDRBAK, HdrType, HdrCreator, HdrBakRef, Err);
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
end;
OpenEnd(MSGTXT, TxtRef, TxtFileEnd, Err);
BeginTotal := HdrFileEnd div HdrSize;
HdrRecCount := HdrFileEnd div sizeof(HdrBuf);
HdrHdl := HdrBufHdl(NewHandle(sizeOf(HdrBuf)));
Err := MemError;
if Err <> NoErr then
NoMem;
MoveHHi(Handle(HdrHdl));
HLock(Handle(HdrHdl));
TestMem := nil;
if Err <> NoErr then
TestMem := NewHandle(Max);
Err := MemError;
if Err <> NoErr then
begin
if (TestMem <> nil) then
DisposHandle(TestMem);
TestMem := NewHandle(Med);
Err := MemError;
if Err <> NoErr then
begin
if (TestMem <> nil) then
DisposHandle(TestMem);
TestMem := NewHandle(Min);
Err := MemError;
if Err <> NoErr then
NoMem
else
TBufSize := Min
end
else
TBufSize := Med
end
else
TBufSize := Max;
if (TestMem <> nil) then
DisposHandle(TestMem);
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
debugStr1 := 'Got memory';
if DEBUG then
IncrementDebug;
TxtHdl := NewHandle(TBufSize);
Err := MemError;
if Err <> NoErr then
NoMem;
MoveHHi(Handle(TxtHdl));
HLock(Handle(TxtHdl));
debugStr1 := 'Got buffer';
if DEBUG then
IncrementDebug;
{ Next section reads HdrRecCount + 1 records -- the + 1 makes sure it }
{ grabs the last part of the file, since Xfer is automatically }
{ adjusted by FSRead to reflect actual numbers of characters read. }
for Counter := 1 to HdrRecCount + 1 do
begin
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
Xfer := sizeof(HdrBuf);
Err := FSRead(HdrRef, Xfer, Ptr(HdrHdl^));
if not (Defaults[4] in ['P', '0'..'5']) then
Err := FSWrite(HdrBakRef, Xfer, Ptr(HdrHdl^));
HeaderCount := Xfer div HdrSize;
for BuffCount := 1 to HeaderCount do
begin
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
OneHeader := HdrHdl^^[BuffCount];
TheSection := OneHeader.Section[1];
if IsActive(OneHeader, LocalPrivSect, NetPrivSect) then
SectStats[TheSection].count := succ(SectStats[TheSection].count);
end; { for BuffCount := 1 to (Xfer div HdrSize) }
end; { for Counter := 1 to HdrRecCount + 1 }
if not (Defaults[4] in ['P', '0'..'5']) then
Err := FSClose(HdrBakRef);
if DEBUG then
IncrementDebug;
StatusBox.right := (StatusBox.left + StatusLength div 5);
FillRect(StatusBox, gray);
if not (Defaults[4] in ['P', '0'..'5']) then
begin
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
TempString := 'msgtxt';
EraseRect(MsgNoRect);
ForeColor(RedColor);
TextBox(Pointer(ord(@TempString) + 1), length(TempString), MsgNoRect, teJustRight);
ForeColor(BlueColor);
TFileIn := 0;
TFileOut := 0;
Err := GetFInfo(MSGTXT, DefaultVol, MsgFndrInfo);
TxtType := MsgFndrInfo.fdType;
TxtCreator := MsgFndrInfo.fdCreator;
ResetFile(MSGTXTBAK, TxtType, TxtCreator, TxtBakRef, Err);
TxtRecCount := TxtFileEnd div TBufSize;
if TxtRecCount > 0 then
begin
for Counter := 1 to TxtRecCount + 1 do
begin
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
FillTxtBuff;
Err := SetFPos(TxtBakRef, FSFromStart, TFileOut);
Err := FSWrite(TxtBakRef, Xfer, Ptr(TxtHdl^));
TFileOut := TFileOut + Xfer;
StatusBox.right := (StatusBox.left + StatusLength div 5 + ((StatusLength * 8 * Counter) div (10 * TxtRecCount)));
if StatusBox.right > StatusBox.left + StatusLength then
StatusBox.right := StatusBox.left + StatusLength;
FillRect(StatusBox, gray);
end; { for Counter := 1 to TxtRecCount + 1 }
end; { if TxtRecCount > 0 }
Err := FSClose(TxtBakRef);
end; { if not (Defaults[4] in ['P', '0'..'5']) }
if DEBUG then
IncrementDebug;
StatusBox.right := StatusBox.left + StatusLength;
FillRect(StatusBox, gray);
HUnLock(Handle(TxtHdl));
for Counter := 1 to 255 do
begin
if MultiFinder & ((Counter mod 25) = 0) then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
SectStats[Counter].newcount := SectStats[Counter].count;
if SectStats[Counter].Limit = 0 then
SectStats[Counter].Adjust := 0
else if SectStats[Counter].Limit = -1 then
SectStats[Counter].Adjust := 30000 { Big number deletes all }
else if SectStats[Counter].Count > SectStats[Counter].Limit then
SectStats[Counter].Adjust := SectStats[Counter].Count - SectStats[Counter].Limit
else
SectStats[Counter].Adjust := 0
end;
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
if DEBUG then
IncrementDebug;
DrawDialog(theDialog);
TextFont(Geneva);
TextSize(9);
ForeColor(RedColor);
TempString := concat('version ', mehitVersion);
TextBox(Pointer(ord(@TempString) + 1), length(TempString), Box, teJustLeft);
ForeColor(BlueColor);
GetDItem(theDialog, 2, ItemType, Item, ProgressBox); { UserItem guide for thermometer }
FrameRect(ProgressBox);
TextFont(0);
TextSize(12);
TempString := 'mehitabel: cleaning…';
EraseRect(StatusRect);
TextBox(Pointer(ord(@TempString) + 1), length(TempString), StatusRect, teJustLeft);
TextFont(Monaco);
TextSize(9);
ForeColor(RedColor);
HFileIn := 0;
HFileOut := 0;
HBufOut := 0;
TFileIn := 0;
TFileOut := 0;
TBufOut := 0;
SurplusTotal := 0;
TooOldTotal := 0;
DeleteTotal := 0;
LoMsgNo := 0;
HiMsgNo := 0;
MsgErrs := 0;
TextArcCount := 0;
Orphans := false;
OrphanTotal := 0;
DisplayCount := 10;
OneHeader.MsgNo := 0; { display garbage preventer if there are no active headers }
Undeletes := 0;
CurrentNum := 1;
FillTxtBuff;
TxOffset := 0; { Use to track buffer to text in file }
if DefaultsPtr^.Renumber then
myMNAHdl := MNAHdl(newHandle(SizeOf(MNA) + (SizeOf(OldNum) * (HdrRecCount - 1))));
Err := MemError;
if Err <> NoErr then
NoMem;
debugStr1 := 'Doing headers';
if DEBUG then
IncrementDebug;
for Counter := 1 to HdrRecCount + 1 do
begin
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
Xfer := sizeof(HdrBuf);
StatusBox.right := (StatusBox.left + ((StatusLength * Counter) div (HdrRecCount + 2)));
if StatusBox.right > StatusBox.left + StatusLength then
StatusBox.right := StatusBox.left + StatusLength;
ForeColor(BlueColor);
FillRect(StatusBox, black);
ForeColor(RedColor);
Err := SetFPos(HdrRef, FSFromStart, HFileIn);
Err := FSRead(HdrRef, Xfer, Ptr(HdrHdl^));
HFileIn := HFileIn + Xfer;
HeaderCount := Xfer div HdrSize;
HBufOut := 0;
HBufIn := 0;
for BuffCount := 1 to HeaderCount do
begin
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
OneHeader := HdrHdl^^[BuffCount];
if OneHeader.Section[1] < 1 then
OneHeader.Section[1] := 255;
TheSection := OneHeader.Section[1];
if DisplayCount = 10 then
begin
TempString := StringOf(OneHeader.MsgNo : 1);
EraseRect(MsgNoRect);
TextBox(Pointer(ord(@TempString) + 1), length(TempString), MsgNoRect, teJustRight);
DisplayCount := 1;
end
else
DisplayCount := succ(DisplayCount);
Deleted := false;
HeaderErr := false;
Valid := false;
for ValidCount := 1 to SectionCount do
if Sections[ValidCount]^^.Number = TheSection then
begin
Valid := true;
Leave
end;
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
if not Valid then
begin
Orphans := true;
OrphanSect[TheSection] := true;
OrphanTotal := succ(OrphanTotal);
end;
if (OneHeader.MsgNo < LoMsgNo) | (OneHeader.MsgNo > HiMsg) then
HeaderErr := true
else if (OneHeader.BeginText + OneHeader.LengthText) > TxtFileEnd then
HeaderErr := true
else if OneHeader.LengthText > MaxTextLength then
HeaderErr := true
else if (OneHeader.BeginText < 0) | (OneHeader.LengthText < 0) then
HeaderErr := true;
if HeaderErr = true then
begin
Deleted := true;
MsgErrs := succ(MsgErrs);
DErr[TheSection] := succ(DErr[TheSection]);
if SectStats[TheSection].Adjust > 0 then
SectStats[TheSection].Adjust := pred(SectStats[TheSection].Adjust);
SectStats[TheSection].NewCount := pred(SectStats[TheSection].NewCount);
if DefaultsPtr^.LogErrors then
LogMsgErrors;
end;
if Valid & (HeaderErr = false) then
begin
{*** altered 6/18/90 to not delete last message w/ (OneHeader.MsgNo < HiMsg) ***}
{*** altered 2/10/91 to undelete public messages on request ***}
if (not IsActive(OneHeader, LocalPrivSect, NetPrivSect)) & (OneHeader.MsgNo < HiMsg) then
begin {don't clip last message -- leave for next time!}
Deleted := true;
DeleteTotal := succ(DeleteTotal);
SectStats[TheSection].Deletes := succ(SectStats[TheSection].Deletes);
end
else if SectStats[TheSection].Adjust > 0 then { adjust limit }
begin
Deleted := true;
DLimit[TheSection] := succ(DLimit[TheSection]);
SectStats[TheSection].Adjust := pred(SectStats[TheSection].Adjust);
SectStats[TheSection].NewCount := pred(SectStats[TheSection].NewCount);
SurplusTotal := succ(SurplusTotal);
end
else if SectStats[TheSection].Age > 0 then { check age }
begin
with TempTime do
begin
month := ord(OneHeader.TimeRcvd[1]);
day := ord(OneHeader.TimeRcvd[2]);
year := ord(OneHeader.TimeRcvd[3]) + 1900;
hour := ord(OneHeader.TimeRcvd[4]);
minute := ord(OneHeader.TimeRcvd[5]);
second := ord(OneHeader.TimeRcvd[6]);
dayOfWeek := 1;
end; { with TempTime }
Date2Secs(TempTime, TempSecs);
if ((NowSecs - TempSecs) div DAYSECS) > SectStats[TheSection].Age then
begin
Deleted := true;
DAge[TheSection] := succ(DAge[TheSection]);
if SectStats[TheSection].Adjust > 0 then
SectStats[TheSection].Adjust := pred(SectStats[TheSection].Adjust);
SectStats[TheSection].NewCount := pred(SectStats[TheSection].NewCount);
TooOldTotal := succ(TooOldTotal)
end
end { check age }
end; { if Valid & (HeaderErr = false) }
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
if not Deleted then
begin
if DefaultsPtr^.Renumber then
begin
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
SetHandleSize(Handle(myMNAHdl), (SizeOf(MNA) + (SizeOf(OldNum) * (CurrentNum - 1))));
MoveHHi(Handle(myMNAHdl));
HLock(Handle(myMNAHdl));
myMNAHdl^^.OldNumbers[CurrentNum] := OneHeader.MsgNo;
myMNAHdl^^.HowMany := CurrentNum;
OneHeader.MsgNo := CurrentNum;
CurrentNum := succ(CurrentNum);
if (BitAnd(OneHeader.Status[1], Reply) = Reply) then { message is a reply }
begin
ReplyCounter := 0;
repeat
ReplyCounter := succ(ReplyCounter);
until (OneHeader.ReplyTo = myMNAHdl^^.OldNumbers[ReplyCounter]) | (ReplyCounter = CurrentNum); { old number in first array }
if (OneHeader.ReplyTo = myMNAHdl^^.OldNumbers[ReplyCounter]) then
OneHeader.ReplyTo := ReplyCounter
else
OneHeader.Status[1] := BitAnd(OneHeader.Status[1], BitNot(Reply))
end; { if (BitAnd(OneHeader.Status[1], Reply) = Reply) }
HUnlock(Handle(myMNAHdl));
with HdrHdl^^[BuffCount] do
begin
MsgNo := OneHeader.MsgNo;
ReplyTo := OneHeader.ReplyTo
end;
end;
if LoMsgNo = 0 then
LoMsgNo := OneHeader.MsgNo;
HiMsgNo := OneHeader.MsgNo;
TBufIn := OneHeader.BeginText - TxOffset;
TxLen := OneHeader.LengthText;
with HdrHdl^^[BuffCount] do
begin
BeginText := TFileOut + TBufOut;
Status := OneHeader.Status;
end;
TransferText;
if HBufOut <> HBufIn then
begin
MLoc := ord(HdrHdl^);
BlockMove(Ptr(MLoc + HBufIn), Ptr(MLoc + HBufOut), Size(HdrSize));
end; { if HBufOut < HBufIn }
HBufOut := HBufOut + HdrSize;
end { if not deleted }
else if (SectStats[TheSection].Backup = true) & (HeaderErr = false) then
begin
MsgToText(OneHeader, TxtRef);
TextArcCount := succ(TextArcCount);
DBU[TheSection] := succ(DBU[TheSection]);
end;
HBufIn := HBufIn + HdrSize;
end; { for BuffCount := 1 to (Xfer div HdrSize) }
Err := SetFPos(HdrRef, FSFromStart, HFileOut);
Err := FSWrite(HdrRef, HBufOut, Ptr(HdrHdl^));
HFileOut := HFileOut + HBufOut;
end; { for Counter := 1 to HdrRecCount + 1 }
debugStr1 := 'Done with headers';
if DEBUG then
IncrementDebug;
Xfer := TBufOut;
Err := SetFPos(TxtRef, FSFromStart, TFileOut);
MoveHHi(Handle(TxtHdl));
HLock(Handle(TxtHdl));
Err := FSWrite(TxtRef, Xfer, Ptr(TxtHdl^));
TFileOut := TFileOut + Xfer;
Err := SetEOF(HdrRef, HFileOut);
Err := SetEOF(TxtRef, TFileOut);
Err := FSClose(HdrRef);
Err := FSClose(TxtRef);
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
NewActiveCount := 0;
for MsgCount := 1 to SectionCount do
NewActiveCount := NewActiveCount + SectStats[Sections[MsgCount]^^.Number].NewCount;
NewActiveCount := NewActiveCount + OrphanTotal;
{ Update message counter with last message number }
TempString := StringOf(OneHeader.MsgNo : 1);
EraseRect(MsgNoRect);
TextBox(Pointer(ord(@TempString) + 1), length(TempString), MsgNoRect, teJustRight);
if (HdrHdl <> nil) then
begin
HUnlock(Handle(HdrHdl));
DisposHandle(Handle(HdrHdl));
end;
if NewActiveCount = 0 then
begin { if there are no active messages, Host }
LoMsgNo := $00FFFFFF; { expects the low number to be 00FFFFFF }
HiMsgNo := 0;
end;
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
debugStr1 := 'Updating message counts';
if DEBUG then
IncrementDebug;
Err := FSOpen(MESSAGES, DefaultVol, MsgsRef);
Err := SetFPos(MsgsRef, fsFromStart, 50);
ThreeLongs[1] := LoMsgNo;
ThreeLongs[2] := HiMsgNo;
ThreeLongs[3] := TFileOut;
Xfer := 12;
Err := FSWrite(MsgsRef, Xfer, @ThreeLongs);
Err := FSClose(MsgsRef);
if LoMsgNo = $00FFFFFF then { restore zero value for reports }
LoMsgNo := 0;
if Defaults[4] = 'K' then
begin
Err := FSDelete(MESSAGESBAK, DefaultVol);
Err := FSDelete(MSGHDRBAK, DefaultVol);
Err := FSDelete(MSGTXTBAK, DefaultVol);
end;
StringToNum(DefaultsPtr^.MaxBUSize, BULimit);
if BULimit > 0 then
begin
BULimit := 1024 * BULimit;
TrimTextFiles;
end;
SetPort(theDialog);
StatusBox.right := StatusBox.left + StatusLength;
ForeColor(BlueColor);
FillRect(StatusBox, black);
debugStr1 := 'Writing reports';
if DEBUG then
IncrementDebug;
if Orphans = true then
OrphanReport;
ElapsedTime := (TickCount - ElapsedTime) div 60;
if DEBUG then
IncrementDebug;
TextFont(0);
TextSize(12);
if DefaultsPtr^.FullLog then
begin
TempString := 'mehitabel: writing report…';
EraseRect(StatusRect);
TextBox(Pointer(ord(@TempString) + 1), length(TempString), StatusRect, teJustLeft);
WriteBigReport;
end;
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
if DEBUG then
IncrementDebug;
if DefaultsPtr^.BriefLog then
begin
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
TempString := 'mehitabel: writing report…';
EraseRect(StatusRect);
TextBox(Pointer(ord(@TempString) + 1), length(TempString), StatusRect, teJustLeft);
WriteBriefReport;
end;
if DEBUG then
IncrementDebug;
if DefaultsPtr^.WriteToTabby then
begin
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
TempString := 'mehitabel: writing log…';
EraseRect(StatusRect);
TextBox(Pointer(ord(@TempString) + 1), length(TempString), StatusRect, teJustLeft);
OldActiveCount := 0;
for MsgCount := 1 to SectionCount do
OldActiveCount := OldActiveCount + SectStats[Sections[MsgCount]^^.Number].Count;
TimeStamp;
HUnLock(Handle(TxtHdl));
MoveHHi(Handle(TxtHdl));
HLock(Handle(TxtHdl));
MLoc := ord(TxtHdl^);
TFileIn := 0;
TempString := concat(DateString, ' mehitabel - ', StringOf(OldActiveCount + DeleteTotal : 1), ' messages processed', ENDLINE);
LineLength := length(TempString);
BlockMove(Ptr(ord(@TempString) + 1), Ptr(MLoc + TFileIn), Size(LineLength));
TFileIn := TFileIn + LineLength;
TempString := concat(DateString, ' mehitabel - ', StringOf(DeleteTotal + SurplusTotal + TooOldTotal + MsgErrs : 1), ' messages purged', ENDLINE);
LineLength := length(TempString);
BlockMove(Ptr(ord(@TempString) + 1), Ptr(MLoc + TFileIn), Size(LineLength));
TFileIn := TFileIn + LineLength;
TempString := concat(DateString, ' mehitabel - ', StringOf(NewActiveCount : 1), ' messages active', ENDLINE);
LineLength := length(TempString);
BlockMove(Ptr(ord(@TempString) + 1), Ptr(MLoc + TFileIn), Size(LineLength));
TFileIn := TFileIn + LineLength;
Err := FSOpen(concat(gDefaultPath, 'Tabby:Tabby Log'), DefaultVol, TLogRef);
Err := SetFPos(TLogRef, fsFromLEOF, 0);
Err := FSWrite(TLogRef, TFileIn, Ptr(TxtHdl^));
Err := FSClose(TLogRef);
end;
if (TxtHdl <> nil) then
begin
HUnlock(TxtHdl);
DisposHandle(TxtHdl);
end;
debugStr1 := 'Doing users';
if DEBUG then
IncrementDebug;
if DefaultsPtr^.ProcessUL then
ProcessUserLog;
UnloadSeg(@ProcessUserLog);
debugStr1 := 'Doing text files';
if DEBUG then
IncrementDebug;
if (DefaultsPtr^.ResetCL | DefaultsPtr^.ResetTL) then
ProcessTextFiles;
UnloadSeg(@ProcessTextFiles);
if DefaultsPtr^.WriteToTabby then
begin
TimeStamp;
Err := FSOpen(concat(gDefaultPath, 'Tabby:Tabby Log'), DefaultVol, TLogRef);
Err := SetFPos(TLogRef, fsFromLEOF, 0);
Err := WrLn(TLogRef, concat(DateString, ' mehitabel - program ending'));
Err := FSClose(TLogRef);
end;
DisposDialog(theDialog);
if DEBUG then
CloseDebug;
if MultiFinder then
IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil)
end; { Backup Procedure }
end. { Backup Unit }